package com.spsoft.vatoutinv.service.flowprocess;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.bo.TokenUser;
import com.spsoft.core.model.leqidmz.param.ApplyCreditParams;
import com.spsoft.core.model.leqidmz.param.BaseNsrRequestParams;
import com.spsoft.core.model.ProcessParamBo;
import com.spsoft.core.utils.SecurityUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.model.vo.vmscreditlimit.VmsCreditlimitVO;
import com.spsoft.vatoutinv.service.vmscreditlimit.VmsCreditLimitService;
import com.spsoft.vatoutinv.service.vmsenterpriseinfo.VmsEnterpriseInfoService;
import com.spsoft.vatoutinv.service.vmsfulloutinvoice.VmsFullOutInvoiceDetailsService;
import com.spsoft.vms.redis.service.BswjRedisService;
import com.spsoft.workflow.common.enums.BusFlowTypeEnums;
import com.spsoft.workflow.common.enums.bus.CreditRollBackNodeEnums;
import com.spsoft.workflow.service.BusinessHandlerService;
import com.spsoft.workflow.service.ProcessBusinessService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**
 * 手动流程处理业务实现类，bean，取自
 * BusFlowTypeEnums.FLOW_THSXED
 * 退回授信额度
 *
 * @author cdl
 * @date 2023/12/15
 */
@Service("FLOW_THSXED")
@Slf4j
@RequiredArgsConstructor
public class CreditRollBackProcessHandlerServiceImpl implements BusinessHandlerService {

    private final ProcessBusinessService processBusinessService;

    private final BswjRedisService bswjRedisService;

    private final VmsCreditLimitService vmsCreditLimitService;

    private final VmsEnterpriseInfoService vmsEnterpriseInfoService;

    private final VmsFullOutInvoiceDetailsService vmsFullOutInvoiceDetailsService;

    /**
     * 直连单位ID
     */
    @Value("${leqi.zldwId}")
    private String zldwId;

    @Override
    public void processHandler(ProcessParamBo pp) throws BusinessException {
        Long busId=pp.getBusId();
        String busDataJson=pp.getBusData();
        String nodeId=pp.getNodeId();
        CreditRollBackNodeEnums e = CreditRollBackNodeEnums.valueOfCode(nodeId);
        if (e == null) {
            throw new BusinessException(ResponseEnum.PARAM_VALIDATED_ERROR.getCode(), "审批流程有误，请联系管理员。");
        }
        switch (e) {
            case ROOT:
                /**
                 * 退回授信额度
                 * 1：校验退回的额度是否为正数，保留两位小数（下限 0.01,上限 99999999.99）
                 * 2：若已下载未使用额度＜申请退回额度，返回失败
                 * 3：校验是否有未上传成功的已开发票
                 * 4：授信额度申请流程需要先校验是否有流程中的数据
                 */
                if (StringUtil.isEmpty(busDataJson)) {
                    throw new BusinessException(ResponseEnum.PARAM_VALIDATED_ERROR.getCode(), "申请额度不能为空。");
                }
                // 校验申请下载额度
                BigDecimal applyLimit = JSONObject.parseObject(busDataJson).getBigDecimal("applyLimit");
                boolean success = checkApplyLimit(applyLimit);
                if (!success) {
                    throw new BusinessException(ResponseEnum.CREDIT_LIMIT_NUMBER_ERROR);
                }

                // 查询本地已下载未使用授信额度
                Result<VmsCreditlimitVO> result = vmsCreditLimitService.getCreditLimit();
                BigDecimal downLoadNotUsed = ObjectUtil.isEmpty(result.getData().getYxzwsyed()) ? BigDecimal.ZERO : result.getData().getYxzwsyed();
                if (applyLimit.compareTo(downLoadNotUsed) > 0) {
                    throw new BusinessException(ResponseEnum.CREDIT_LIMIT_ROLLBACK_TOO_MOENY);
                }

                // 校验是否有未上传成功的已开发票
                boolean flag = vmsFullOutInvoiceDetailsService.checkUploadFull(SecurityUtils.getDeptCode());
                if (!flag) {
                    throw new BusinessException(ResponseEnum.CREDIT_LIMIT_APPLY_ERROR);
                }

                // 校验是否有流程中的数据
                BusFlowTypeEnums busFlowTypeEnums = BusFlowTypeEnums.FLOW_THSXED;
                boolean processNotFinished = processBusinessService.isProcessNotEnd(SecurityUtils.getDeptCode(), busId, busFlowTypeEnums);
                if (processNotFinished) {
                    throw new BusinessException(ResponseEnum.CREDIT_LIMIT_PROCESS_ROLLBACK_NOT_FINISH);
                }
                break;
            case FLOW_THSXED_SP:
                /**
                 * 审批逻辑
                 * 若已下载未使用额度＜申请退回额度
                 * 申请退回授信额度流程提交失败！申请退回授信额度应小于机构当前已下载未使用额度！
                 */
                if (StringUtil.isEmpty(busDataJson)) {
                    throw new BusinessException(ResponseEnum.PARAM_VALIDATED_ERROR.getCode(), "申请额度不能为空。");
                }
                BigDecimal apply = JSONObject.parseObject(busDataJson).getBigDecimal("applyLimit");

                // 查询本地已下载未使用授信额度
                Result<VmsCreditlimitVO> result2 = vmsCreditLimitService.getCreditLimit();
                BigDecimal downLoadNotUsed2 = ObjectUtil.isEmpty(result2.getData().getYxzwsyed()) ? BigDecimal.ZERO : result2.getData().getYxzwsyed();
                if (apply.compareTo(downLoadNotUsed2) > 0) {
                    throw new BusinessException(ResponseEnum.CREDIT_LIMIT_ROLLBACK_TOO_MOENY);
                }
                break;
            case FLOW_THSXED_TH:
                // 调用乐企接口下载/退回授信额度
                TokenUser tokenUser = SecurityUtils.getTokenUser();
                // 获取使用单位编号
                String sydwbh = bswjRedisService.getSydwbh(tokenUser.getDeptCode());

                ApplyCreditParams param = new ApplyCreditParams();
                param.setPtbh(sydwbh);
                param.setYwlsh(sydwbh + zldwId + RandomUtil.randomString(32));
                param.setSqlx(CommonEnum.CREDIT_LIMIT_APPLY_TYPE_1.getKey());
                param.setSqed(JSONObject.parseObject(busDataJson).getBigDecimal("applyLimit"));
                param.setNsrsbh(vmsEnterpriseInfoService.getNsrsbh());
                param.setCreateUser(tokenUser.getUserCode());
                param.setDeptCode(tokenUser.getDeptCode());
                Result<Object> dmzResult = vmsCreditLimitService.applyCreditLimitByLq(param, tokenUser);
                if (!ResponseEnum.SUCCESS.getCode().equals(dmzResult.getCode())) {
                    throw new BusinessException(dmzResult.getCode(), dmzResult.getMessage());
                }

                // 调用乐企查询最新的授信额度
                BaseNsrRequestParams queryParam = new BaseNsrRequestParams();
                queryParam.setNsrsbh(param.getNsrsbh());
                queryParam.setCreateUser(tokenUser.getUserCode());
                queryParam.setDeptCode(tokenUser.getDeptCode());
                log.info("调用乐企接口查询授信额度，入参：{}", JSONObject.toJSONString(queryParam));
                Result<Object> leqiResult = vmsCreditLimitService.getCreditLimitByLq(queryParam, tokenUser);
                log.info("调用乐企接口查询授信额度，出参：{}", JSONObject.toJSONString(leqiResult));
                break;
            default:
                // 未知节点报错
                throw new BusinessException(ResponseEnum.PROCESS_NODE_ERROR);
        }
    }

    /**
     * 校验申请的额度是否满足条件
     * 需要为正数，保留两位小数（下限 0.01,上限 99999999.99）
     */
    private boolean checkApplyLimit(BigDecimal applyLimit) {
        // 正数
        if (ObjectUtil.isEmpty(applyLimit) || applyLimit.compareTo(BigDecimal.ZERO) <= 0) {
            return false;
        }
        // 获取小数位数，需要保留两位小数
        int decimalDigits = Math.max(applyLimit.stripTrailingZeros().scale(), 0);
        if (decimalDigits > 2) {
            return false;
        }

        // 边界值
        BigDecimal lowerBound = new BigDecimal("0.01");
        BigDecimal upperBound = new BigDecimal("99999999.99");
        return applyLimit.compareTo(lowerBound) >= 0 && applyLimit.compareTo(upperBound) <= 0;
    }
}
